Prerequisites

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ──────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5     ✓ purrr   0.3.4
✓ tibble  3.1.6     ✓ dplyr   1.0.7
✓ tidyr   1.1.4     ✓ stringr 1.4.0
✓ readr   2.1.0     ✓ forcats 0.5.1
── Conflicts ─────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

First steps

Do cars with big engines use more fuel than cars with small engines?

The mpg data frame

mpg

Creating a ggplot

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy))

Exercises

1. Run ggplot(data = mpg). What do you see?

ggplot(data = mpg)

2. How many rows are in mpg? How many columns?

# rows
nrow(mpg)
[1] 234
# columns
ncol(mpg)
[1] 11

3. What does the drv variable describe? Read the help for ?mpg to find out?

glimpse(mpg)
Rows: 234
Columns: 11
$ manufacturer <chr> "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi"…
$ model        <chr> "a4", "a4", "a4", "a4", "a4", "a4", "a4", "a4 quattro", "a4 quattro", "a4 quattro", "a4 quattr…
$ displ        <dbl> 1.8, 1.8, 2.0, 2.0, 2.8, 2.8, 3.1, 1.8, 1.8, 2.0, 2.0, 2.8, 2.8, 3.1, 3.1, 2.8, 3.1, 4.2, 5.3,…
$ year         <int> 1999, 1999, 2008, 2008, 1999, 1999, 2008, 1999, 1999, 2008, 2008, 1999, 1999, 2008, 2008, 1999…
$ cyl          <int> 4, 4, 4, 4, 6, 6, 6, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8…
$ trans        <chr> "auto(l5)", "manual(m5)", "manual(m6)", "auto(av)", "auto(l5)", "manual(m5)", "auto(av)", "man…
$ drv          <chr> "f", "f", "f", "f", "f", "f", "f", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "r",…
$ cty          <int> 18, 21, 20, 21, 16, 18, 18, 18, 16, 20, 19, 15, 17, 17, 15, 15, 17, 16, 14, 11, 14, 13, 12, 16…
$ hwy          <int> 29, 29, 31, 30, 26, 26, 27, 26, 25, 28, 27, 25, 25, 25, 25, 24, 25, 23, 20, 15, 20, 17, 17, 26…
$ fl           <chr> "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r",…
$ class        <chr> "compact", "compact", "compact", "compact", "compact", "compact", "compact", "compact", "compa…

4. Make a scatterplot of hwy vs cyl.

ggplot(data = mpg, aes(x = cyl, y = hwy)) +
  geom_point()

5. What happens if you make a scatterplot of class vs drv? Why is the plot not useful?

ggplot(data = mpg, aes(x = class, y = drv)) +
  geom_point()

Aesthetic mappings

ggplot(data = mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point()

ggplot(data = mpg, aes(x = displ, y = hwy, size = class)) +
  geom_point()
Warning: Using size for a discrete variable is not advised.

# Left
ggplot(data = mpg, aes(x = displ, y = hwy, alpha = class)) +
  geom_point()
Warning: Using alpha for a discrete variable is not advised.

# Right
ggplot(data = mpg, aes(x = displ, y = hwy, shape = class)) +
  geom_point()
Warning: The shape palette can deal with a maximum of 6 discrete values because more than 6 becomes difficult to
discriminate; you have 7. Consider specifying shapes manually if you must have them.
Warning: Removed 62 rows containing missing values (geom_point).

ggplot(data = mpg, aes(x = displ, y = hwy)) +
  geom_point(color = "blue")

Exercises

1. What’s wrong with this code? Why are the points not blue?

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, color = "blue"))

The manual color setting needs to be outside of the aes argument.

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy), color = "blue")

2. Which variables in mpg are categorical? Which variables are continuous? How can you see this information when you run mpg?

glimpse(mpg)
Rows: 234
Columns: 11
$ manufacturer <chr> "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi", "audi"…
$ model        <chr> "a4", "a4", "a4", "a4", "a4", "a4", "a4", "a4 quattro", "a4 quattro", "a4 quattro", "a4 quattr…
$ displ        <dbl> 1.8, 1.8, 2.0, 2.0, 2.8, 2.8, 3.1, 1.8, 1.8, 2.0, 2.0, 2.8, 2.8, 3.1, 3.1, 2.8, 3.1, 4.2, 5.3,…
$ year         <int> 1999, 1999, 2008, 2008, 1999, 1999, 2008, 1999, 1999, 2008, 2008, 1999, 1999, 2008, 2008, 1999…
$ cyl          <int> 4, 4, 4, 4, 6, 6, 6, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8…
$ trans        <chr> "auto(l5)", "manual(m5)", "manual(m6)", "auto(av)", "auto(l5)", "manual(m5)", "auto(av)", "man…
$ drv          <chr> "f", "f", "f", "f", "f", "f", "f", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "r",…
$ cty          <int> 18, 21, 20, 21, 16, 18, 18, 18, 16, 20, 19, 15, 17, 17, 15, 15, 17, 16, 14, 11, 14, 13, 12, 16…
$ hwy          <int> 29, 29, 31, 30, 26, 26, 27, 26, 25, 28, 27, 25, 25, 25, 25, 24, 25, 23, 20, 15, 20, 17, 17, 26…
$ fl           <chr> "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "r",…
$ class        <chr> "compact", "compact", "compact", "compact", "compact", "compact", "compact", "compact", "compa…

3. Map a continuous variable to color, size, and shape. How do these aesthetics behave differently for categorical vs. continuous variables?

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, color = year))


ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, size = year))


ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, shape = year))
Error: A continuous variable can not be mapped to shape
Run `rlang::last_error()` to see where the error occurred.

4. What happens if you map the same variable to multiple aesthetics?

5. What does the stroke aesthetic do? What shapes does it work with?

6. What happens if you map an aesthetic to something other than a variable name, like aes(color = displ < 5)? Note, you’ll also need to specify x and y.

Common problems

Facets

ggplot(data = mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_grid(drv ~ cyl)

Exercises

1. What happens if you facet on a continuous variable?

ggplot(data = mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ cty)

It facets along all combinations of the variable.

2. What do the empty cells in plot with facet_grid(drv ~ cyl) mean? How do they relate to this plot?

It means that there is no data in the combination of variables.

3. What plots does the following code make? What does the . do?

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_grid(drv ~ .)


ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_grid(. ~ cyl)

The . allows the user to specify facets by rows or columns.

4. Take the first faceted plot in this section:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) + 
  facet_wrap(~ class, nrow = 2)

What are the advantages to using faceting instead of the color aesthetic? What are the disadvantages? How might the balance change if you had a larger dataset?

5. Read ?facet_wrap. What does nrow do? What does ncol do? What other options control the layout of the individual panels? Why doesn’t facet_grid() have nrow and ncol arguments?

6. When using facet_grid() you should usually put the variable with more unique levels in the columns. Why?

Geometric objects

Exercises

1. What deom would you use to draw a line chart?

geom_line()

A boxplot?

geom_boxplot()

A histogram?

geom_histogram()

An area chart?

geom_area()

2. Run this code in your head and predict what the output will look like. Then, rune the code in R and check you predictions.

This code will produce a scatterplot with a fitted line.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) + 
  geom_point() + 
  geom_smooth(se = FALSE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

3. What does show.legend = FALSE do? What happens if you remove it? Why do you think I used it earlier in the chapter?

show_legend supresses the legend mappings.

4. What does the se argument to geom_smooth() do?

It contols the standard error shading in the plot.

5. Will these two graphs look different? Why/why not?

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point() + 
  geom_smooth()
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

ggplot() + 
  geom_point(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_smooth(data = mpg, mapping = aes(x = displ, y = hwy))
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

No, they will produce the same plot.

6. Recreate the R code necessary to generate the following graphs.

(plot1 + plot2) / (plot3 + plot4) / (plot5 + plot6)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Statistical transformations

Exercises

1. What is the default geom associated with stat_summary()? How could you rewrite the previous plot to use that geom function instead of the stat function?

The default is geom_pointrange() and the default stat for this geom is identity().

ggplot(data = diamonds) +
  geom_pointrange(aes(x = cut, y = depth), stat = "summary")
No summary function supplied, defaulting to `mean_se()`

3. Most geoms and stats come in pairs that are almost always used in concert. Read through the documentation and make a list for all the pairs. What do they have in common?

4. What variables does stat_smooth() compute? What parameters control its behavior?

It computes a predicted value, a confidence interval and and standard error.

5. In our proportion bar chart, we need to set group = 1. Why? In other words what is the problem with these two graphs?

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, y = after_stat(prop)))


ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, fill = color, y = after_stat(prop)))

Position adjustments

LS0tCnRpdGxlOiAiRGF0YSB2aXN1YWxpc2F0aW9uIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIFByZXJlcXVpc2l0ZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgojIEZpcnN0IHN0ZXBzCgpEbyBjYXJzIHdpdGggYmlnIGVuZ2luZXMgdXNlIG1vcmUgZnVlbCB0aGFuIGNhcnMgd2l0aCBzbWFsbCBlbmdpbmVzPwoKIyMgVGhlIGBtcGdgIGRhdGEgZnJhbWUKCmBgYHtyfQptcGcKYGBgCgojIyBDcmVhdGluZyBhIGdncGxvdAoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpCmBgYAoKIyMgRXhlcmNpc2VzCgoqKjEuICBSdW4gYGdncGxvdChkYXRhID0gbXBnKWAuIFdoYXQgZG8geW91IHNlZT8qKgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKQpgYGAKCioqMi4gIEhvdyBtYW55IHJvd3MgYXJlIGluIGBtcGdgPyBIb3cgbWFueSBjb2x1bW5zPyoqCgpgYGB7cn0KIyByb3dzCm5yb3cobXBnKQoKIyBjb2x1bW5zCm5jb2wobXBnKQpgYGAKCioqMy4gIFdoYXQgZG9lcyB0aGUgYGRydmAgdmFyaWFibGUgZGVzY3JpYmU/IFJlYWQgdGhlIGhlbHAgZm9yIGA/bXBnYCB0byBmaW5kIG91dD8qKgoKYGBge3J9CmdsaW1wc2UobXBnKQpgYGAKCioqNC4gTWFrZSBhIHNjYXR0ZXJwbG90IG9mIGBod3lgIHZzIGBjeWxgLioqCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIGFlcyh4ID0gY3lsLCB5ID0gaHd5KSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCioqNS4gV2hhdCBoYXBwZW5zIGlmIHlvdSBtYWtlIGEgc2NhdHRlcnBsb3Qgb2YgYGNsYXNzYCB2cyBgZHJ2YD8gV2h5IGlzIHRoZSBwbG90IG5vdCB1c2VmdWw/KioKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgYWVzKHggPSBjbGFzcywgeSA9IGRydikpICsKICBnZW9tX3BvaW50KCkKYGBgCgojIEFlc3RoZXRpYyBtYXBwaW5ncwoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGNsYXNzKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgc2l6ZSA9IGNsYXNzKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCmBgYHtyfQojIExlZnQKZ2dwbG90KGRhdGEgPSBtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGFscGhhID0gY2xhc3MpKSArCiAgZ2VvbV9wb2ludCgpCgojIFJpZ2h0CmdncGxvdChkYXRhID0gbXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBzaGFwZSA9IGNsYXNzKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gImJsdWUiKQpgYGAKCiMjIEV4ZXJjaXNlcwoKKioxLiBXaGF0J3Mgd3Jvbmcgd2l0aCB0aGlzIGNvZGU/IFdoeSBhcmUgdGhlIHBvaW50cyBub3QgYmx1ZT8qKgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gImJsdWUiKSkKYGBgCgpUaGUgbWFudWFsIGNvbG9yIHNldHRpbmcgbmVlZHMgdG8gYmUgb3V0c2lkZSBvZiB0aGUgYGFlc2AgYXJndW1lbnQuIAoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLCBjb2xvciA9ICJibHVlIikKYGBgCgoqKjIuIFdoaWNoIHZhcmlhYmxlcyBpbiBgbXBnYCBhcmUgY2F0ZWdvcmljYWw/IFdoaWNoIHZhcmlhYmxlcyBhcmUgY29udGludW91cz8gSG93IGNhbiB5b3Ugc2VlIHRoaXMgaW5mb3JtYXRpb24gd2hlbiB5b3UgcnVuIGBtcGdgPyoqCgpgYGB7cn0KZ2xpbXBzZShtcGcpCmBgYAoKKiozLiBNYXAgYSBjb250aW51b3VzIHZhcmlhYmxlIHRvIGBjb2xvcmAsIGBzaXplYCwgYW5kIGBzaGFwZWAuIEhvdyBkbyB0aGVzZSBhZXN0aGV0aWNzIGJlaGF2ZSBkaWZmZXJlbnRseSBmb3IgY2F0ZWdvcmljYWwgdnMuIGNvbnRpbnVvdXMgdmFyaWFibGVzPyoqCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSB5ZWFyKSkKCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIHNpemUgPSB5ZWFyKSkKCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIHNoYXBlID0geWVhcikpCmBgYAoKKio0LiBXaGF0IGhhcHBlbnMgaWYgeW91IG1hcCB0aGUgc2FtZSB2YXJpYWJsZSB0byBtdWx0aXBsZSBhZXN0aGV0aWNzPyoqCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBkaXNwbCwgc2l6ZSA9IGh3eSkpCmBgYAoKKio1LiBXaGF0IGRvZXMgdGhlIGBzdHJva2VgIGFlc3RoZXRpYyBkbz8gV2hhdCBzaGFwZXMgZG9lcyBpdCB3b3JrIHdpdGg/KioKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBzdHJva2UgPSAyKSwgc2hhcGUgPSAyMSkKYGBgCgoqKjYuIFdoYXQgaGFwcGVucyBpZiB5b3UgbWFwIGFuIGFlc3RoZXRpYyB0byBzb21ldGhpbmcgb3RoZXIgdGhhbiBhIHZhcmlhYmxlIG5hbWUsIGxpa2UgYGFlcyhjb2xvciA9IGRpc3BsIDwgNSlgPyBOb3RlLCB5b3UnbGwgYWxzbyBuZWVkIHRvIHNwZWNpZnkgeCBhbmQgeS4qKgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCAKICAgICAgIGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gZGlzcGwgPCA1KSkgKyAKICBnZW9tX3BvaW50KCkKYGBgCgojIENvbW1vbiBwcm9ibGVtcwoKIyBGYWNldHMKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZmFjZXRfd3JhcCh+IGNsYXNzLCBucm93ID0gMikKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKGRydiB+IGN5bCkKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKGRydiB+IGN5bCkKYGBgCgojIyBFeGVyY2lzZXMKCioqMS4gV2hhdCBoYXBwZW5zIGlmIHlvdSBmYWNldCBvbiBhIGNvbnRpbnVvdXMgdmFyaWFibGU/KioKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF93cmFwKH4gY3R5KQpgYGAKCkl0IGZhY2V0cyBhbG9uZyBhbGwgY29tYmluYXRpb25zIG9mIHRoZSB2YXJpYWJsZS4gCgoqKjIuIFdoYXQgZG8gdGhlIGVtcHR5IGNlbGxzIGluIHBsb3Qgd2l0aCBgZmFjZXRfZ3JpZChkcnYgfiBjeWwpYCBtZWFuPyBIb3cgZG8gdGhleSByZWxhdGUgdG8gdGhpcyBwbG90PyoqCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkcnYsIHkgPSBjeWwpKQpgYGAKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKGRydiB+IGN5bCkKYGBgCgpJdCBtZWFucyB0aGF0IHRoZXJlIGlzIG5vIGRhdGEgaW4gdGhlIGNvbWJpbmF0aW9uIG9mIHZhcmlhYmxlcy4gCgoqKjMuIFdoYXQgcGxvdHMgZG9lcyB0aGUgZm9sbG93aW5nIGNvZGUgbWFrZT8gV2hhdCBkb2VzIHRoZSBgLmAgZG8/KioKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoZHJ2IH4gLikKCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZmFjZXRfZ3JpZCguIH4gY3lsKQpgYGAKClRoZSBgLmAgYWxsb3dzIHRoZSB1c2VyIHRvIHNwZWNpZnkgZmFjZXRzIGJ5IHJvd3Mgb3IgY29sdW1ucy4gCgoqKjQuIFRha2UgdGhlIGZpcnN0IGZhY2V0ZWQgcGxvdCBpbiB0aGlzIHNlY3Rpb246KioKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKyAKICBmYWNldF93cmFwKH4gY2xhc3MsIG5yb3cgPSAyKQpgYGAKCioqV2hhdCBhcmUgdGhlIGFkdmFudGFnZXMgdG8gdXNpbmcgZmFjZXRpbmcgaW5zdGVhZCBvZiB0aGUgY29sb3IgYWVzdGhldGljPyBXaGF0IGFyZSB0aGUgZGlzYWR2YW50YWdlcz8gSG93IG1pZ2h0IHRoZSBiYWxhbmNlIGNoYW5nZSBpZiB5b3UgaGFkIGEgbGFyZ2VyIGRhdGFzZXQ/KioKCioqNS4gUmVhZCBgP2ZhY2V0X3dyYXBgLiBXaGF0IGRvZXMgYG5yb3dgIGRvPyBXaGF0IGRvZXMgYG5jb2xgIGRvPyBXaGF0IG90aGVyIG9wdGlvbnMgY29udHJvbCB0aGUgbGF5b3V0IG9mIHRoZSBpbmRpdmlkdWFsIHBhbmVscz8gV2h5IGRvZXNuJ3QgYGZhY2V0X2dyaWQoKWAgaGF2ZSBgbnJvd2AgYW5kIGBuY29sYCBhcmd1bWVudHM/KioKCioqNi4gV2hlbiB1c2luZyBgZmFjZXRfZ3JpZCgpYCB5b3Ugc2hvdWxkIHVzdWFsbHkgcHV0IHRoZSB2YXJpYWJsZSB3aXRoIG1vcmUgdW5pcXVlIGxldmVscyBpbiB0aGUgY29sdW1ucy4gV2h5PyoqCgojIEdlb21ldHJpYyBvYmplY3RzCgojIyBFeGVyY2lzZXMKCioqMS4gV2hhdCBkZW9tIHdvdWxkIHlvdSB1c2UgdG8gZHJhdyBhIGxpbmUgY2hhcnQ/KioKCmBnZW9tX2xpbmUoKWAKCioqQSBib3hwbG90PyoqCgpgZ2VvbV9ib3hwbG90KClgCgoqKkEgaGlzdG9ncmFtPyoqCgpgZ2VvbV9oaXN0b2dyYW0oKWAKCioqQW4gYXJlYSBjaGFydD8qKgoKYGdlb21fYXJlYSgpYAoKKioyLiBSdW4gdGhpcyBjb2RlIGluIHlvdXIgaGVhZCBhbmQgcHJlZGljdCB3aGF0IHRoZSBvdXRwdXQgd2lsbCBsb29rIGxpa2UuIFRoZW4sIHJ1bmUgdGhlIGNvZGUgaW4gUiBhbmQgY2hlY2sgeW91IHByZWRpY3Rpb25zLioqCgpUaGlzIGNvZGUgd2lsbCBwcm9kdWNlIGEgc2NhdHRlcnBsb3Qgd2l0aCBhIGZpdHRlZCBsaW5lLiAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gZHJ2KSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQpgYGAKCioqMy4gV2hhdCBkb2VzIGBzaG93LmxlZ2VuZCA9IEZBTFNFYCBkbz8gV2hhdCBoYXBwZW5zIGlmIHlvdSByZW1vdmUgaXQ/IFdoeSBkbyB5b3UgdGhpbmsgSSB1c2VkIGl0IGVhcmxpZXIgaW4gdGhlIGNoYXB0ZXI/KioKCmBzaG93X2xlZ2VuZGAgc3VwcmVzc2VzIHRoZSBsZWdlbmQgbWFwcGluZ3MuIAoKKio0LiBXaGF0IGRvZXMgdGhlIGBzZWAgYXJndW1lbnQgdG8gYGdlb21fc21vb3RoKClgIGRvPyoqCgpJdCBjb250b2xzIHRoZSBzdGFuZGFyZCBlcnJvciBzaGFkaW5nIGluIHRoZSBwbG90LiAKCioqNS4gV2lsbCB0aGVzZSB0d28gZ3JhcGhzIGxvb2sgZGlmZmVyZW50PyBXaHkvd2h5IG5vdD8qKgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9zbW9vdGgoKQoKZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKyAKICBnZW9tX3Ntb290aChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpCmBgYAoKTm8sIHRoZXkgd2lsbCBwcm9kdWNlIHRoZSBzYW1lIHBsb3QuIAoKKio2LiBSZWNyZWF0ZSB0aGUgUiBjb2RlIG5lY2Vzc2FyeSB0byBnZW5lcmF0ZSB0aGUgZm9sbG93aW5nIGdyYXBocy4qKgoKYGBge3J9CnBsb3QxIDwtIAogIGdncGxvdChkYXRhID0gbXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDQpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQoKcGxvdDIgPC0gCiAgZ2dwbG90KGRhdGEgPSBtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCkgKwogIGdlb21fc21vb3RoKGFlcyhncm91cCA9IGRydiksIHNlID0gRkFMU0UpCgpwbG90MyA8LSAKICBnZ3Bsb3QoZGF0YSA9IG1wZywgYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBkcnYpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCkgKwogIGdlb21fc21vb3RoKGFlcyhncm91cCA9IGRydiksIHNlID0gRkFMU0UpCgpwbG90NCA8LSAKICBnZ3Bsb3QoZGF0YSA9IG1wZywgYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBnZW9tX3BvaW50KHNpemUgPSA0LCBhZXMoY29sb3IgPSBkcnYpKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSkKCnBsb3Q1IDwtIAogIGdncGxvdChkYXRhID0gbXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydikpICsKICBnZW9tX3BvaW50KHNpemUgPSA0KSArCiAgZ2VvbV9zbW9vdGgoYWVzKGxpbmV0eXBlID0gZHJ2KSwgc2UgPSBGQUxTRSkKCnBsb3Q2IDwtIAogIGdncGxvdChkYXRhID0gbXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydikpICsKICBnZW9tX3BvaW50KHNpemUgPSA0LCBjb2xvciA9ICJ3aGl0ZSIpICsKICBnZW9tX3BvaW50KCkKCmxpYnJhcnkocGF0Y2h3b3JrKQoKKHBsb3QxICsgcGxvdDIpIC8gKHBsb3QzICsgcGxvdDQpIC8gKHBsb3Q1ICsgcGxvdDYpCmBgYAoKIyBTdGF0aXN0aWNhbCB0cmFuc2Zvcm1hdGlvbnMKCiMjIEV4ZXJjaXNlcwoKKioxLiBXaGF0IGlzIHRoZSBkZWZhdWx0IGdlb20gYXNzb2NpYXRlZCB3aXRoIGBzdGF0X3N1bW1hcnkoKWA/IEhvdyBjb3VsZCB5b3UgcmV3cml0ZSB0aGUgcHJldmlvdXMgcGxvdCB0byB1c2UgdGhhdCBnZW9tIGZ1bmN0aW9uIGluc3RlYWQgb2YgdGhlIHN0YXQgZnVuY3Rpb24/KioKClRoZSBkZWZhdWx0IGlzIGBnZW9tX3BvaW50cmFuZ2UoKWAgYW5kIHRoZSBkZWZhdWx0IHN0YXQgZm9yIHRoaXMgZ2VvbSBpcyBgaWRlbnRpdHkoKWAuIAoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHggPSBjdXQsIHkgPSBkZXB0aCksIHN0YXQgPSAic3VtbWFyeSIpCmBgYAoKKiozLiBNb3N0IGdlb21zIGFuZCBzdGF0cyBjb21lIGluIHBhaXJzIHRoYXQgYXJlIGFsbW9zdCBhbHdheXMgdXNlZCBpbiBjb25jZXJ0LiBSZWFkIHRocm91Z2ggdGhlIGRvY3VtZW50YXRpb24gYW5kIG1ha2UgYSBsaXN0IGZvciBhbGwgdGhlIHBhaXJzLiBXaGF0IGRvIHRoZXkgaGF2ZSBpbiBjb21tb24/KioKCioqNC4gV2hhdCB2YXJpYWJsZXMgZG9lcyBgc3RhdF9zbW9vdGgoKWAgY29tcHV0ZT8gV2hhdCBwYXJhbWV0ZXJzIGNvbnRyb2wgaXRzIGJlaGF2aW9yPyoqCgpJdCBjb21wdXRlcyBhIHByZWRpY3RlZCB2YWx1ZSwgYSBjb25maWRlbmNlIGludGVydmFsIGFuZCBhbmQgc3RhbmRhcmQgZXJyb3IuCgoqKjUuIEluIG91ciBwcm9wb3J0aW9uIGJhciBjaGFydCwgd2UgbmVlZCB0byBzZXQgYGdyb3VwID0gMWAuIFdoeT8gSW4gb3RoZXIgd29yZHMgd2hhdCBpcyB0aGUgcHJvYmxlbSB3aXRoIHRoZXNlIHR3byBncmFwaHM/KioKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArIAogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IGFmdGVyX3N0YXQocHJvcCkpKQoKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIGZpbGwgPSBjb2xvciwgeSA9IGFmdGVyX3N0YXQocHJvcCkpKQpgYGAKCiMgUG9zaXRpb24gYWRqdXN0bWVudHMKCg==